//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V0.2.1
#include "soft_i2c_bsp.h"
#include <string.h>
#include <stdlib.h>


typedef struct
{
    void (*GPIO_Init_CB)(void);//引脚必须开漏模式
    void (*GPIO_Set_State_CB)(WHT_Soft_I2C_BUS_GPIO_enum io, WHT_Sort_I2C_BUS_IO_State_enum state);//设置引脚状态
    WHT_Sort_I2C_BUS_IO_State_enum (*GPIO_Get_State_CB)(WHT_Soft_I2C_BUS_GPIO_enum io);            //获取引脚状态
}WHT_I2C_GPIO_t;

/*软I2C总线结构体*/
typedef struct
{
    WHT_Soft_I2C_BUS_t Info; //总线信息
    unsigned int Delay_Count;//延迟时间
    WHT_I2C_GPIO_t GPIO;     //总线GPIO
}WHT_I2C_BUS_Private_t;

#define WHT_BUS        ((WHT_I2C_BUS_Private_t*)bus)

#define I2C_ACK   0
#define I2c_NACK  1

#ifndef NULL
#define NULL ((void*)0)
#endif

static WHT_I2C_BUS_Private_t* WHT_I2C_BUS[3] = {0};//I2C总线3个


/*软I2C波特率延迟控制*/
static void WHT_Soft_I2C_Delay(WHT_Soft_I2C_BUS_t* bus)
{
    unsigned int count;

    count = WHT_BUS->Delay_Count;
    while (count--);
}
/*软I2C起始信号*/
static void WHT_Soft_I2C_Start(WHT_Soft_I2C_BUS_t* bus)
{
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SDA, Soft_I2C_IO_Low);
    WHT_Soft_I2C_Delay(bus);
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Low);
}
/*软I2C重复起始信号*/
static void WHT_Soft_I2C_Restart(WHT_Soft_I2C_BUS_t* bus)
{
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Low);
    WHT_Soft_I2C_Delay(bus);
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Hig);
    WHT_Soft_I2C_Delay(bus);
    WHT_Soft_I2C_Start(bus);
}
/*软I2C发送1个字节*/
static void WHT_Soft_I2C_Send_1Byte(WHT_Soft_I2C_BUS_t* bus, unsigned char datax)
{
    for (unsigned char i = 0x80; i != 0; i >>= 1)
    {
        WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Low);//拉低时钟
        if (datax & i)
            WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SDA, Soft_I2C_IO_Hig);
        else
            WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SDA, Soft_I2C_IO_Low);
        WHT_Soft_I2C_Delay(bus);
        WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Hig);//拉高时钟
        WHT_Soft_I2C_Delay(bus);
    }
}
/*软I2C接收1个字节*/
static void WHT_Soft_I2C_Receive_1Byte(WHT_Soft_I2C_BUS_t* bus, unsigned char* receive_buff)
{
    receive_buff[0] = 0;
    for (unsigned char i = 0x80; i != 0; i >>= 1)
    {
        WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Low);//拉低时钟
        WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SDA, Soft_I2C_IO_Hig);//释放总线
        WHT_Soft_I2C_Delay(bus);
        WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Hig);//拉高时钟
        if (WHT_BUS->GPIO.GPIO_Get_State_CB(Soft_I2C_SDA))
            receive_buff[0] |= i;
        WHT_Soft_I2C_Delay(bus);
    }
}
/*软I2C获取从设备应答ACK*/
static void WHT_Soft_I2C_Get_ACK(WHT_Soft_I2C_BUS_t* bus)
{
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Low);//拉低时钟
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SDA, Soft_I2C_IO_Hig);//释放总线
    WHT_Soft_I2C_Delay(bus);
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Hig);//拉高时钟
    if (WHT_BUS->GPIO.GPIO_Get_State_CB(Soft_I2C_SDA))
        *(WHT_Soft_I2C_BUS_State_enum*)&WHT_BUS->Info.State = Soft_I2C_Slave_No_ACK;
    else
        *(WHT_Soft_I2C_BUS_State_enum*)&WHT_BUS->Info.State = Soft_I2C_No_Error;
    WHT_Soft_I2C_Delay(bus);
}
/*软I2C发送ACK或NACK*/
static void WHT_Soft_I2C_Set_ACK(WHT_Soft_I2C_BUS_t* bus, unsigned char ack_flag)
{
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Low);//拉低时钟
    if (ack_flag == I2C_ACK)
        WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SDA, Soft_I2C_IO_Low);//拉低数据
    WHT_Soft_I2C_Delay(bus);
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Hig);//拉高时钟
    WHT_Soft_I2C_Delay(bus);
}
/*软I2C结束信号*/
static void WHT_Soft_I2C_Stop(WHT_Soft_I2C_BUS_t* bus)
{
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Low);
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SDA, Soft_I2C_IO_Low);
    WHT_Soft_I2C_Delay(bus);
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Hig);
    WHT_Soft_I2C_Delay(bus);
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SDA, Soft_I2C_IO_Hig);//时钟高电平期间数据线的拉高将产生结束信号
    WHT_Soft_I2C_Delay(bus);
}




/*总线速率设置*/
static void WHT_Soft_I2C_Bus_Set_Rate(WHT_Soft_I2C_BUS_t* bus)
{
    WHT_BUS->Delay_Count = ((float)WHT_BUS->Info.Config.Sys_Rate_Hz / 2 / (float)(WHT_BUS->Info.Config.I2C_Rate_Hz) / 14);//延迟时间
}
/*总线从设备个数*/
static char WHT_Soft_I2C_Bus_Scan_Mount_Count(WHT_Soft_I2C_BUS_t* bus)
{
    char i2c_slave_count = 0;
    unsigned char addr_7bit = 0x00;

    *(WHT_Soft_I2C_BUS_Lock_enum*)&WHT_BUS->Info.Mutex = Soft_I2C_Lock;
    *(WHT_Soft_I2C_BUS_State_enum*)&WHT_BUS->Info.State = Soft_I2C_No_Error;

    //判断总线是否空闲
    if ((WHT_BUS->GPIO.GPIO_Get_State_CB(Soft_I2C_SCL) == Soft_I2C_IO_Low) || (WHT_BUS->GPIO.GPIO_Get_State_CB(Soft_I2C_SDA) == Soft_I2C_IO_Low))
    {
        *(WHT_Soft_I2C_BUS_State_enum*)&WHT_BUS->Info.State = Soft_I2C_BUS_Error;
        goto Game_Over;
    }

    do//发送设备地址
    {
        WHT_Soft_I2C_Start(bus);//发送开始信号
        WHT_Soft_I2C_Send_1Byte(bus, addr_7bit << 1);//发送设备地址(write)
        WHT_Soft_I2C_Get_ACK(bus);//获取应答
        WHT_Soft_I2C_Stop(bus);//发送结束信号
        if (WHT_BUS->Info.State != Soft_I2C_Slave_No_ACK)
            i2c_slave_count++;
        if (addr_7bit++ == (0xff >> 1))
            break;
    } while (1);

Game_Over:
    *(WHT_Soft_I2C_BUS_Lock_enum*)&WHT_BUS->Info.Mutex = Soft_I2C_Unlock;
    return i2c_slave_count;
}
/*总线初始化*/
static void WHT_Soft_I2C_Bus_Init(WHT_Soft_I2C_BUS_t* bus)
{
    WHT_Soft_I2C_Bus_Set_Rate(bus);
    WHT_BUS->GPIO.GPIO_Init_CB();
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SCL, Soft_I2C_IO_Hig);
    WHT_BUS->GPIO.GPIO_Set_State_CB(Soft_I2C_SDA, Soft_I2C_IO_Hig);
    *(WHT_Soft_I2C_BUS_Lock_enum*)&WHT_BUS->Info.Mutex = Soft_I2C_Unlock;
}
/*注册软件I2C总线*/
static WHT_Soft_I2C_BUS_t* WHT_Soft_I2C_BUS_Register(char* name, WHT_Soft_I2C_BUS_Config_t* config, void (*gpio_init_callback)(void),
                                                    void (*gpio_set_callback)(WHT_Soft_I2C_BUS_GPIO_enum io, WHT_Sort_I2C_BUS_IO_State_enum state),
                                                    WHT_Sort_I2C_BUS_IO_State_enum (*gpio_get_callback)(WHT_Soft_I2C_BUS_GPIO_enum io))
{
    char Pos;

    if ((strcmp(name, WHT_Soft_I2C1_Name) == 0) && (WHT_I2C_BUS[0] == NULL))
        Pos = 0;
    else if ((strcmp(name, WHT_Soft_I2C2_Name) == 0) && (WHT_I2C_BUS[1] == NULL))
        Pos = 1;
    else if ((strcmp(name, WHT_Soft_I2C3_Name) == 0) && (WHT_I2C_BUS[2] == NULL))
        Pos = 2;
    else
        return NULL;
    
    WHT_I2C_BUS[Pos] = malloc(sizeof(WHT_I2C_BUS_Private_t));
    if (WHT_I2C_BUS[Pos])
    {
        WHT_I2C_BUS[Pos]->Info.Name = name;
        memcpy(&WHT_I2C_BUS[Pos]->Info, config, sizeof(WHT_Soft_I2C_BUS_Config_t));
        WHT_I2C_BUS[Pos]->GPIO.GPIO_Init_CB = gpio_init_callback;
        WHT_I2C_BUS[Pos]->GPIO.GPIO_Set_State_CB = gpio_set_callback;
        WHT_I2C_BUS[Pos]->GPIO.GPIO_Get_State_CB = gpio_get_callback;
        WHT_Soft_I2C_Bus_Init((WHT_Soft_I2C_BUS_t*)WHT_I2C_BUS[Pos]);
        return (WHT_Soft_I2C_BUS_t*)WHT_I2C_BUS[Pos];
    }
    return NULL;
}
/*注销软件I2C总线*/
static void WHT_Soft_I2C_BUS_Unregister(WHT_Soft_I2C_BUS_t* bus)
{
    if (WHT_I2C_BUS[0] == WHT_BUS)
        WHT_I2C_BUS[0] = NULL;
    else if (WHT_I2C_BUS[1] == WHT_BUS)
        WHT_I2C_BUS[1] = NULL;
    else if (WHT_I2C_BUS[2] == WHT_BUS)
        WHT_I2C_BUS[2] = NULL;
    else
        return;
    free(WHT_BUS);
}



/*写命令*/
static unsigned char WHT_Soft_I2C_Write_Cmd(WHT_Soft_I2C_BUS_t* bus, WHT_Soft_I2C_Cache_t* cache)
{
    //检测总线状态
    if ((WHT_BUS->GPIO.GPIO_Get_State_CB(Soft_I2C_SCL) == Soft_I2C_IO_Low) || (WHT_BUS->GPIO.GPIO_Get_State_CB(Soft_I2C_SDA) == Soft_I2C_IO_Low))
    {
        *(WHT_Soft_I2C_BUS_State_enum*)&WHT_BUS->Info.State = Soft_I2C_BUS_Error;
        return 1;
    }
    
    WHT_Soft_I2C_Start(bus);  //发送开始信号
    WHT_Soft_I2C_Send_1Byte(bus, cache->Addr_7Bit << 1);//发送设备地址(write)
    WHT_Soft_I2C_Get_ACK(bus);//获取应答
    if (WHT_BUS->Info.State == Soft_I2C_Slave_No_ACK)
        return 1;

    //发送命令
    for (unsigned char i = 0; i < cache->Cmd_Count; i++)
    {
        WHT_Soft_I2C_Send_1Byte(bus, cache->Cmd[i]);
        WHT_Soft_I2C_Get_ACK(bus);
        if (WHT_BUS->Info.State == Soft_I2C_Slave_No_ACK)
            return 1;
    }
    return 0;
}
/*I2C阻塞读写*/
static void WHT_Soft_I2C_Read_Write(WHT_Soft_I2C_BUS_t* bus, WHT_Soft_I2C_Cache_t* cache)
{
    unsigned int count;

    *(WHT_Soft_I2C_BUS_Lock_enum*)&WHT_BUS->Info.Mutex = Soft_I2C_Lock;
    *(WHT_Soft_I2C_BUS_State_enum*)&WHT_BUS->Info.State = Soft_I2C_No_Error;
    if (WHT_Soft_I2C_Write_Cmd(bus, cache) != 0)
        goto Game_Over;
    if (cache->Buffer_Count == 0)
        goto Game_Over;

    if (cache->Dir == Soft_I2C_Read)
    {
        WHT_Soft_I2C_Restart(bus);//发送重复开始信号
        WHT_Soft_I2C_Send_1Byte(bus, (cache->Addr_7Bit << 1) | 1);//发送设备地址(read)
        WHT_Soft_I2C_Get_ACK(bus);//获取应答
        if (WHT_BUS->Info.State == Soft_I2C_Slave_No_ACK)
            goto Game_Over;
        for (count = 0; count < cache->Buffer_Count; count++)//读取数据
        {
            WHT_Soft_I2C_Receive_1Byte(bus, cache->Buffer + count);
            if ((count+1) == cache->Buffer_Count)
                //发送非应答
                WHT_Soft_I2C_Set_ACK(bus, I2c_NACK);
            else
                WHT_Soft_I2C_Set_ACK(bus, I2C_ACK);
        }
    }
    else
    {
        for (count = 0; count < cache->Buffer_Count; count++)//发送数据
        {
            WHT_Soft_I2C_Send_1Byte(bus, cache->Buffer[count]);
            WHT_Soft_I2C_Get_ACK(bus);
            if (WHT_BUS->Info.State == Soft_I2C_Slave_No_ACK)
                goto Game_Over;
        }
    }
Game_Over:
    WHT_Soft_I2C_Stop(bus);//发送结束信号
    *(WHT_Soft_I2C_BUS_Lock_enum*)&WHT_BUS->Info.Mutex = Soft_I2C_Unlock;
}


/*全局常量*/
const WHT_Soft_I2C_BUS_OPS_t WHT_Soft_I2C_BUS_OPS =
{
    .Register         = WHT_Soft_I2C_BUS_Register,
    .Unregister       = WHT_Soft_I2C_BUS_Unregister,
    .Set_Rate         = WHT_Soft_I2C_Bus_Set_Rate,
    .Scan_Mount_Count = WHT_Soft_I2C_Bus_Scan_Mount_Count,
    .Read_Write       = WHT_Soft_I2C_Read_Write,
};
